package douyin

import (
	"GoServer/utils/config"
	"GoServer/utils/databases"
	"GoServer/utils/debug"
	"GoServer/utils/tool"
	"context"
	"crypto/md5"
	"encoding/base64"
	"encoding/json"
	"fmt"

	"sort"
	"strings"
	"time"
)

/*
*
请求小玩法access_token
*/
type RequsetToken struct {
	Appid     string `json:"appid"`      //小程序 ID
	Secret    string `json:"secret"`     //小程序的 APP Secret，可以在开发者后台获取
	GrantType string `json:"grant_type"` //获取 access_token 时值为 client_credential
}

type DouyinTokenBody struct {
	ErrorCode int64       `json:"err_no"`
	ErrorTips string      `json:"err_tips"`
	Data      AccessToken `json:"data"`
}
type AccessToken struct {
	Token     string `json:"access_token"`
	ExpiresIn int64  `json:"expires_in"`
	ExpiresAt int64  `json:"expiresAt"`
}

//var DYAccessToken string = "080112184633413238794e6b6f6236693239592b534f676574513d3d" /// access_token

func GetDYAccessToken(gameName string) string {
	value, err := databases.Rediss.Get(context.Background(), gameName+"AccessToken").Result()
	if err != nil {
		return ""
	}

	return value
}

// / 初始化抖音Access_token刷新定时器
func RefreshAccessToken(gameName string) {
	tool.Timer(
		time.Duration(config.GetConfig("app").GetInt("douyin.DelayRefreshTime"))*time.Second,
		time.Duration(config.GetConfig("app").GetInt("douyin.refreshAccessToken"))*time.Second,
		GetAccessToken,
		map[string]string{
			"game_name": gameName,
		})
}

func GetAccessToken(param interface{}) (result bool) {
	params, ok := param.(map[string]string)
	if !ok {
		fmt.Println("参数格式错误")
		return false
	}
	game_name := params["game_name"]
	result = true
	defer func() {
		if r := recover(); !tool.InterfaceIsNil(r) {
			debug.Logln(debug.Error, "cleanConnection err", r)
		}
	}()
	debug.Logln(debug.Info, "定时刷新抖音access_token")
	data := &RequsetToken{
		Appid:     config.GetConfig("app").GetString(game_name + ".appid"),
		Secret:    config.GetConfig("app").GetString(game_name + ".appSecret"),
		GrantType: config.GetConfig("app").GetString("douyin.grantType"),
	}
	reqBody, err := json.Marshal(data)
	if err != nil {
		debug.Logln(debug.Error, "Json to Byte error :", err)
	}
	jsonStr := string(reqBody)
	debug.Logln(debug.Info, "定时请求access_tokenres:", jsonStr)

	/// 这里暂时注释掉， 用抖音给的结果测试
	headers := map[string]string{
		"content-type": "application/json",
	}
	res, err := tool.SendPostRetry(3, time.Duration(3)*time.Second, config.GetConfig("app").GetString("douyin.getAccessTokenUrl"), jsonStr, headers)
	if err != nil {
		debug.Logln(debug.Error, err.Error())
	}
	//res := []byte(`{"err_no":0,"err_tips":"success","data":{"access_token":"080112184631574a414732725a324139775158695852316f45513d3d","expires_in":7200,"expiresAt":1681407870}}`)
	msg := DouyinTokenBody{}
	if err := json.Unmarshal(res, &msg); err != nil {
		debug.Logln(debug.Error, err.Error())
	}
	debug.Logln(debug.Info, fmt.Sprintf("获取Access_token: %+v", msg))
	///记录抖音的token
	saveAccessToke(game_name, msg.Data.Token, msg.Data.ExpiresIn)

	return true
}

func saveAccessToke(gameName string, accessToken string, expires int64) {
	err := databases.Rediss.Set(context.Background(), gameName+"AccessToken", accessToken, time.Duration(expires)*time.Second).Err()
	if err != nil {
		debug.Logln(debug.Error, "Access Token 存入 redis 失败")
	}
}

/*
*
比如：

	header := map[string]string{
	             "x-nonce-str": "123456",
	             "x-timestamp": "456789",
	             "x-roomid":    "268",
	             "x-msg-type":  "live_gift",
	     }
	bodyStr := "abc123你好"
	secret := "123abc"

rawData为：x-msg-type=live_gift&x-nonce-str=123456&x-roomid=268&x-timestamp=456789abc123你好123abc
signature为：PDcKhdlsrKEJif6uMKD2dw==
*/
func Signature(header map[string]string, bodyStr, secret string) string {
	keyList := make([]string, 0, 4)
	for key, _ := range header {
		keyList = append(keyList, key)
	}

	sort.Slice(keyList, func(i, j int) bool {
		return keyList[i] < keyList[j]
	})

	kvList := make([]string, 0, 4)
	for _, key := range keyList {
		kvList = append(kvList, key+"="+header[key])
	}

	urlParams := strings.Join(kvList, "&")
	rawData := urlParams + bodyStr + secret
	md5Result := md5.Sum([]byte(rawData))

	return base64.StdEncoding.EncodeToString(md5Result[:])
}
